package dj.dao.impl;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.persistence.Column;
import javax.persistence.JoinColumn;
import javax.persistence.Table;

import org.apache.struts2.ServletActionContext;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import dj.Constant;
import dj.dao.BaseDao;
import dj.model.OperateLog;
import dj.pageModel.Puser;
import dj.utils.TableNote;

@Repository("baseDao")
public class BaseDaoImpl<T> implements BaseDao<T> {

	private SessionFactory sessionFactory;

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	private Session getCurrentSession() {
		return sessionFactory.getCurrentSession();
	}

	public Serializable save(T t) {
		Serializable s = this.getCurrentSession().save(t);
		setLog(t, "新增");
		return s;
	}

	public void update(T t) {
		this.getCurrentSession().update(t);
		setLog(t, "更新");
	}

	public void delete(T t) {
		this.getCurrentSession().delete(t);
		setLog(t, "删除");
	}

	public void saveOrUpdate(T t) {
		this.getCurrentSession().saveOrUpdate(t);
		setLog(t, "新增或更新");
	}

	@SuppressWarnings("unchecked")
	public T get(Class<T> c, Serializable id) {
		return (T) this.getCurrentSession().get(c, id);
	}

	public T get(String hql) {
		List<T> ls = find(hql);
		if (null != ls && ls.size() > 0) {
			return ls.get(0);
		}
		return null;
	}

	public T get(String hql, Map<String, Object> params) {
		List<T> ls = find(hql, params);
		if (null != ls && ls.size() > 0) {
			return ls.get(0);
		}
		return null;
	}

	public Long getCount(String hql) {
		return (Long) this.getCurrentSession().createQuery(hql).uniqueResult();
	}

	public Long getCount(String hql, Map<String, Object> params) {
		Query q = this.getCurrentSession().createQuery(hql);
		for (String key : params.keySet()) {
			q.setParameter(key, params.get(key));
		}
		return (Long) q.uniqueResult();
	}

	@SuppressWarnings("unchecked")
	public List<T> find(String hql) {
		Query q = this.getCurrentSession().createQuery(hql);
		List<T> ls = q.list();
		return ls;
	}

	@SuppressWarnings("unchecked")
	public List<T> find(String hql, Map<String, Object> params) {
		Query q = this.getCurrentSession().createQuery(hql);
		for (String key : params.keySet()) {
			q.setParameter(key, params.get(key));
		}
		List<T> ls = q.list();
		return ls;
	}

	@SuppressWarnings("unchecked")
	public List<T> find(String hql, int page, int rows) {
		if (page < 1) {
			page = 1;
		}
		if (rows < 1) {
			rows = 10;
		}
		Query q = this.getCurrentSession().createQuery(hql);
		return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
	}

	@SuppressWarnings("unchecked")
	public List<T> find(String hql, Map<String, Object> params, int page, int rows) {
		if (page < 1) {
			page = 1;
		}
		if (rows < 1) {
			rows = 10;
		}
		Query q = this.getCurrentSession().createQuery(hql);
		for (String key : params.keySet()) {
			q.setParameter(key, params.get(key));
		}
		return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
	}

	public int executeHql(String hql) {
		Query q = this.getCurrentSession().createQuery(hql);
		return q.executeUpdate();
	}

	public int executeHql(String hql, Map<String, Object> params) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (params != null && !params.isEmpty()) {
			for (String key : params.keySet()) {
				q.setParameter(key, params.get(key));
			}
		}
		return q.executeUpdate();
	}

	/**
	 * 自动插入操作日志
	 * 
	 * @param t
	 * @param operateType
	 */
	public void setLog(T t, String operateType) {
		Puser user = null;
		try {
			user = (Puser) ServletActionContext.getRequest().getSession().getAttribute(Constant.USER_SESSION);
		} catch (Exception e1) {
		}
		// 表名
		String tableName = "";
		// 操作字符串
		StringBuffer operateValue = new StringBuffer();
		if (null != user) {
			// 获取表注解
			Annotation[] annos = t.getClass().getAnnotations();

			if (null != annos) {
				for (Annotation ann : annos) {
					if (ann instanceof Table) {
						tableName = ((Table) ann).name();
					}
				}
			}
			// 登录日志，操作日志，表名为空，表注释中没有的表 不进行记录
			if (!"".equals(tableName) && null != TableNote.tableMap.get(tableName)) {
				OperateLog ol = new OperateLog();

				try {
					// 获取类所有column
					BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
					PropertyDescriptor pds[] = beanInfo.getPropertyDescriptors();

					for (int j = 0; j < pds.length; j++) {
						String name = pds[j].getName();
						Method rmethod = pds[j].getReadMethod();
						Method smethoe = pds[j].getWriteMethod();
						try {
							Annotation[] vAnns = t.getClass().getMethod("get" + name.substring(0, 1).toUpperCase() + name.substring(1)).getAnnotations();

							if (null != vAnns) {
								for (Annotation vAnn : vAnns) {
									Object vValue = rmethod.invoke(t);
									//没值不记录
									if(null == vValue || "".equals(vValue)) {
										continue;
									}
									String methodType = "";
									if(smethoe.getParameterTypes().length > 0) {
										methodType = smethoe.getParameterTypes()[0].getName();
									}
									//自定义类 不进行记录
//									if(methodType.length() > 3 && "dj.".equals(methodType.substring(0, 3))) {
//										continue;
//									}
									if("java.util.Date".equals(methodType)) {
										vValue = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(vValue);
									}
									
									if (vAnn instanceof Column) {
										String columnNote = TableNote.columnMap.get(tableName).get(((Column) vAnn).name());
										if (null == columnNote) {
											continue;
										}
										operateValue.append("," + columnNote + ":" + vValue);
									} else if (vAnn instanceof JoinColumn) {
										String columnNote = TableNote.columnMap.get(tableName).get(((JoinColumn) vAnn).name());
										if (null == columnNote) {
											continue;
										}
										//关联表id
										String linkedId = "";
										BeanInfo linkedBean = Introspector.getBeanInfo(vValue.getClass());
										PropertyDescriptor lpds[] = linkedBean.getPropertyDescriptors();
										for (int l = 0; l < lpds.length; l++) {
											String linkName = lpds[l].getName();
											if("id".equals(linkName)) {
												Method linkMethod = lpds[l].getReadMethod();
												linkedId = linkMethod.invoke(vValue) + "";
											}
											
										}
										operateValue.append("," + columnNote + ":" + linkedId);
									}
								}
							}
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
					//插入操作日志
					ol.setId(UUID.randomUUID().toString());
					ol.setUser(user.getName());
					ol.setOperateType(operateType);
					ol.setOperateTime(new Timestamp(new Date().getTime()));
					ol.setObject(TableNote.tableMap.get(tableName));
					ol.setIp(ServletActionContext.getRequest().getRemoteAddr());
					ol.setOperate(operateValue.toString().length() > 1 ? operateValue.toString().substring(1) : operateValue.toString());
					this.getCurrentSession().save(ol);
				} catch (IntrospectionException e) {
				}
			}
		}
	}

}
